package org.glydar.glydar.netty.packet; import io.netty.buffer.ByteBuf; import io.netty.buffer.SlicedByteBuf; import org.glydar.glydar.models.BaseTarget; import org.glydar.glydar.models.EveryoneTarget; import org.glydar.glydar.models.Player; import org.reflections.Reflections; import java.lang.annotation.Annotation; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Constructor; import java.util.HashMap; import java.util.Set; public abstract class CubeWorldPacket { @Retention(RetentionPolicy.RUNTIME) public @interface Packet { int id(); boolean variableLength() default false; } protected boolean doCacheIncoming() { return false; } private int _idCache = -1; public int getID() { if(_idCache < 0) { _idCache = getClass().getAnnotation(CubeWorldPacket.Packet.class).id(); } return _idCache; } private ByteBuf bufCache = null; public void decode(ByteBuf buf) { if(doCacheIncoming()) { int idx = buf.readerIndex(); internalDecode(buf); int newIdx = buf.readerIndex(); bufCache = new SlicedByteBuf(buf, idx, newIdx - idx); } else { internalDecode(buf); } } public void encode(ByteBuf buf) { if(bufCache == null) { int idx = buf.writerIndex(); internalEncode(buf); int newIdx = buf.writerIndex(); bufCache = new SlicedByteBuf(buf, idx, newIdx - idx); } else { bufCache.readerIndex(0); buf.writeBytes(bufCache); } } protected void internalDecode(ByteBuf buf) { throw new IllegalAccessError("Packet cannot be decoded"); } public void receivedFrom(Player ply) { throw new IllegalAccessError("Packet cannot be received"); } protected void internalEncode(ByteBuf buf) { throw new IllegalAccessError("Packet cannot be encoded"); } public void sendTo(Player ply) { bufCache = null; _sendTo(ply); } private void _sendTo(Player ply) { ply.getChannelContext().write(this); } public void sendTo(BaseTarget target) { bufCache = null; for (Player ply : target.getPlayers()) { _sendTo(ply); } } public void sendToAll() { sendTo(EveryoneTarget.INSTANCE); } private static final HashMap<Integer, Constructor<? extends CubeWorldPacket>> CUBE_WORLD_PACKET_HASH_MAP; private static void __addPacketsFromPackage(String pkg) { Reflections refPackage = new Reflections(pkg); Set<Class<? extends CubeWorldPacket>> clientPackets = refPackage.getSubTypesOf(CubeWorldPacket.class); for (Class<? extends CubeWorldPacket> c : clientPackets) { try { Annotation a = c.getAnnotation(CubeWorldPacket.Packet.class); if (a == null) continue; int classID = ((CubeWorldPacket.Packet) a).id(); CUBE_WORLD_PACKET_HASH_MAP.put(classID, c.getConstructor()); } catch (Exception e) { e.printStackTrace(); } } } static { CUBE_WORLD_PACKET_HASH_MAP = new HashMap<Integer, Constructor<? extends CubeWorldPacket>>(); __addPacketsFromPackage("org.glydar.glydar.netty.packet.client"); __addPacketsFromPackage("org.glydar.glydar.netty.packet.shared"); } public static CubeWorldPacket getByID(int id) { try { return CUBE_WORLD_PACKET_HASH_MAP.get(id).newInstance(); } catch (Exception e) { e.printStackTrace(); return null; } } }